﻿using EFFC.Frame.Net.Base.Common;
using EFFC.Frame.Net.Base.Data.Base;
using EFFC.Frame.Net.Module.Extend.EWRA.Attributes;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EFFC.Extends.LinqDLR2SQL;
using EFFC.Frame.Net.Unit.DB;
using ICPFrameLib.Business;
using ICPFrameLib.Common;
using EFFC.Frame.Net.Base.Constants;
using EFFC.Frame.Net.Base.Data;

namespace XHRPMIS.Business.v1._0
{
    public class MyPlugins : MyRestLogic
{
    static object lockobj = new object();
    string _down_root = "PluginsDown";

    [EWRARunMode("Dev,Update")]
    [EWRARoute("get", "/myplugins")]
    [EWRARouteDesc("获取插件列表-从本地中获取")]
    [EWRAAddInput("limit", "int", "每页笔数，当mode为Normal时需要提供", "默认为10", EFFC.Frame.Net.Base.Constants.RestInputPosition.QueryString, true)]
    [EWRAAddInput("page", "int", "指定页数，当mode为Normal时需要提供", "默认为1", EFFC.Frame.Net.Base.Constants.RestInputPosition.QueryString, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
data:{
TotalRow:'总笔数',
CurrentPage:'当前页数',
TotalPage:'总页数',
Count_Of_OnePage:'每页笔数',
data:[{
plugin_no:'插件编号',
title:'插件名称',
description:'描述',
version:'版本',
icp_ver_max:'当前最新版本号',
icp_ver_min:'当前最新版本号',
ui_ver_max:'当前最新版本号',
ui_ver_min:'当前最新版本号',
his_uid:'历史版本PK',
is_load:'是否加载'
from_source:'来源',
uid:'资料ID',
add_time:'新增时间'
}
}")]
    public object GetList()
    {
        SetCacheEnable(false);
        var metaup = DB.NewMetaUnitParameter();
        var result = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                      select new
                      {
                          uid = t.UID,
                          plugin_no = t.Plugin_NO,
                          title = t.Title,
                          version = t.Version,
                          description = t.Description,
                          icp_ver_max = t.ICP_Ver_Max,
                          icp_ver_min = t.ICP_Ver_Min,
                          ui_ver_max = t.UI_Ver_Max,
                          ui_ver_min = t.UI_Ver_Min,
                          his_uid = t.His_UID,
                          is_load = t.Is_Load,
                          from_source = t.From_Source,
                          t.add_time
                      }).QueryByPage(metaup, "add_time desc,title");

        var list = result.QueryData<FrameDLRObject>().Select(d =>
        {
            d.is_load = BoolStd.IsNotBoolThen(d.is_load);
            d.add_time = DateTimeStd.IsDateTimeThen(d.add_time, "yyyy-MM-dd HH:mm:ss");
            return d;
        });

        return ResultHelper.DFormQueryByPageFormat(result.Count_Of_OnePage, result.CurrentPage, result.TotalPage, result.TotalRow, list);
    }

    [EWRARunMode("Dev,Update")]
    [EWRARoute("get", "/myplugins/remote")]
    [EWRARouteDesc("获取插件列表-从RDTP库中获取")]
    [EWRAAddInput("limit", "int", "每页笔数，当mode为Normal时需要提供", "默认为10", EFFC.Frame.Net.Base.Constants.RestInputPosition.QueryString, true)]
    [EWRAAddInput("page", "int", "指定页数，当mode为Normal时需要提供", "默认为1", EFFC.Frame.Net.Base.Constants.RestInputPosition.QueryString, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
data:{
TotalRow:'总笔数',
CurrentPage:'当前页数',
TotalPage:'总页数',
Count_Of_OnePage:'每页笔数',
data:[{
no:'插件编号',
title:'插件名称',
description:'描述',
cur_version:'当前最新版本号',
remark:'备注',
owner:'拥有者',
fit_for:'适用框架模板',
_default_pk:'资料ID',
his:[{
        _default_pk:'资料ID',
        version:'版本号',
        depend_icp_version_min:'依赖ICP最低版本',
        depend_ui_version_min:'依赖UI最低版本',
        depend_icp_version_max:'依赖ICP最大版本',
        depend_ui_version_max:'依赖UI最大版本',
        from_source:'插件包来源'
    }]
}]
}
}")]
    public object GetRemoteList()
    {
        SetCacheEnable(false);
        int limit = IntStd.IsNotIntThen(QueryStringD.limit, 10);
        var page = IntStd.IsNotIntThen(QueryStringD.page, 1);
        var api = new RDTPAPI();
        var str = api.ExcuteGet($"/plugins?limit={limit}&page={page}&fit_for=MIS");
        if (str == "" || str.StartsWith("Failed:"))
        {
            return new
            {
                code = "failed",
                msg = "连接远程服务器失败"
            };
        }
        dynamic result = FrameDLRObject.IsJsonThen(str);
        if (result == null) return new
        {
            code = "failed",
            msg = "访问远程服务器失败"
        };
        if (ComFunc.nvl(result.error) != "")
        {
            return new
            {
                code = "failed",
                msg = $"访问远程服务器失败,错误：{result.error}"
            };
        }
        if (result.result.code == "failed")
        {
            return result.result;
        }
        var list = (IEnumerable<dynamic>)result.result.data;

        return ResultHelper.DFormQueryByPageFormat(IntStd.IsNotIntThen(result.result.limit, 10),
            IntStd.IsNotIntThen(result.result.page, 1),
            IntStd.IsNotIntThen(result.result.total_page),
            IntStd.IsNotIntThen(result.result.total_count),
            list);
    }
    [EWRARunMode("Dev,Update")]
    [EWRARoute("patch", "/myplugins/{id}/dl")]
    [EWRARouteDesc("插件列表-从RDTP库中下载最新得插件到本地")]
    [EWRAAddInput("his_id", "string", "历史版本PK", "默认为当前最新版本", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息'
}")]
    public object DLPlugin(string id)
    {

        var api = new RDTPAPI();
        var str = api.ExcuteSend($"/plugins/{id}/dl", new
        {
            his_id = ""
        }, "Patch");
        if (str == "" || str.StartsWith("Failed:"))
        {
            return new
            {
                code = "failed",
                msg = "连接远程服务器失败"
            };
        }
        dynamic result = FrameDLRObject.IsJsonThen(str);
        if (result == null) return new
        {
            code = "failed",
            msg = "访问远程服务器失败"
        };
        if (ComFunc.nvl(result.error) != "")
        {
            return new
            {
                code = "failed",
                msg = $"访问远程服务器失败,错误：{result.error}"
            };
        }

        if (result.result.code == "failed")
        {
            return result.result;
        }
        var plugin_pk = Guid.NewGuid().ToString();
        var root_path = Path.GetFullPath(_down_root);
        if (!Directory.Exists(root_path)) Directory.CreateDirectory(root_path);
        var plugin_path = Path.Combine(root_path, plugin_pk);

        if (!Directory.Exists(plugin_path)) Directory.CreateDirectory(plugin_path);
        var his_version = new ICPVersion(ComFunc.nvl(result.result.his_version));
        var filename = ComFunc.nvl(result.result.filename);
        var filecontent = ComFunc.Base64DeCodeToByte(result.result.file);

        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        dynamic localinfo = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                             where t.Plugin_NO == result.result.plugin_no
                             orderby t.version descending
                             select new
                             {
                                 uid = t.UID,
                                 plugin_no = t.Plugin_NO,
                                 title = t.Title,
                                 version = t.Version,
                                 icp_ver_max = t.ICP_Ver_Max,
                                 icp_ver_min = t.ICP_Ver_Min,
                                 ui_ver_max = t.UI_Ver_Max,
                                 ui_ver_min = t.UI_Ver_Min,
                                 his_uid = t.His_UID,
                                 is_load = t.Is_Load,
                                 from_source = t.From_Source
                             }).GetQueryList(metaup).FirstOrDefault();

        if (localinfo != null)
        {
            var localversion = new ICPVersion(ComFunc.nvl(localinfo.version));
            if (localversion >= his_version)
            {
                return new
                {
                    code = "failed",
                    msg = $"本地版本高于线上版本，本地版本-{localversion.ToString()},线上版本-{his_version.ToString()}"
                };
            }
            DB.QuickInsert(metaup, "EXTEND_LOCALPLUGIN", new
            {
                UID = plugin_pk,
                Plugin_NO = result.result.plugin_no,
                Title = result.result.plugin_title,
                Version = his_version.ToString(),
                His_UID = result.result.his_pk,
                Is_Load = 0,
                add_id = TokenPayLoad.ID,
                add_name = ComFunc.nvl(TokenPayLoad["name"]),
                add_ip = ClientInfo.IP,
                add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }
        else
        {
            DB.QuickInsert(metaup, "EXTEND_LOCALPLUGIN", new
            {
                UID = plugin_pk,
                Plugin_NO = result.result.plugin_no,
                Title = result.result.plugin_title,
                Version = his_version.ToString(),
                His_UID = result.result.his_pk,
                Is_Load = 0,
                add_id = TokenPayLoad.ID,
                add_name = ComFunc.nvl(TokenPayLoad["name"]),
                add_ip = ClientInfo.IP,
                add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }
        File.WriteAllBytes(Path.Combine(plugin_path, $"{his_version.ToString()}.zip"), filecontent);

        CommitTrans();
        return new
        {
            code = "success",
            msg = "下载成功"
        };
    }
    [EWRARunMode("Dev,Update")]
    [EWRARoute("ws", "/myplugins/upload")]
    [EWRARouteDesc("上传插件包")]
    [EWRAAddInput("id", "string", "插件UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
}")]
    public object UploadPackage()
    {
        //校验SystemSecretKey
        var key = WS.SendInputMsg("请输入系统运维密钥", 120);
        if (key != ComFunc.nvl(Configs["SystemSecretKey"]))
        {
            return new
            {
                code = "failed",
                msg = "系统运维密钥不正确，结束处理"
            };
        }
        var file = WS.SendUploadFileMsgAndRead("请选择插件包", 5 * 60);
        if (string.IsNullOrEmpty(file)) return new
        {
            code = "failed",
            msg = "上传文件无效，终止操作"
        };
        var fileobj = FrameDLRObject.IsJsonThen(file);
        if (fileobj == null) return new
        {
            code = "failed",
            msg = "上传文件格式无效，终止操作"
        };
        var filename = ComFunc.nvl(fileobj.GetValue("filename"));
        var content = ComFunc.nvl(fileobj.GetValue("file"));

        if (Path.GetExtension(filename).Replace(".", "").ToLower() != "zip")
        {
            return new
            {
                code = "failed",
                msg = "请上传zip格式文件"
            };
        }


        var root_path = Path.GetFullPath(_down_root);
        var plugin_pk = Guid.NewGuid().ToString();
        if (!Directory.Exists(root_path)) Directory.CreateDirectory(root_path);
        var plugin_path = Path.Combine(root_path, plugin_pk);

        if (!Directory.Exists(plugin_path)) Directory.CreateDirectory(plugin_path);
        var filecontent = ComFunc.Base64DeCodeToByte(content);
        var desc_json_content = GetFileFromZip(filecontent, "_plugin_desc.json");
        if (desc_json_content == null)
        {
            return new
            {
                code = "failed",
                msg = "上传文件格式无效，缺少描述文件"
            };
        }
        dynamic desc_json = FrameDLRObject.IsJsonThen(ComFunc.ByteToString(desc_json_content, Encoding.UTF8));
        if (desc_json == null)
        {
            return new
            {
                code = "failed",
                msg = "上传文件格式无效，描述文件格式无效"
            };
        }
        var title = "";
        var description = "";
        var version = "";
        var depend_icp_version_max = "";
        var depend_icp_version_min = "";
        var depend_ui_version_min = "";
        var depend_ui_version_max = "";
        var from_source = "";
        var fit_for = "MIS";

        title = ComFunc.nvl(desc_json.title);
        description = ComFunc.nvl(desc_json.description);
        version = ComFunc.nvl(desc_json.version);
        depend_icp_version_max = ComFunc.nvl(desc_json.depend_icp_version_max);
        depend_icp_version_min = ComFunc.nvl(desc_json.depend_icp_version_min);
        depend_ui_version_min = ComFunc.nvl(desc_json.depend_ui_version_min);
        depend_ui_version_max = ComFunc.nvl(desc_json.depend_ui_version_max);
        from_source = ComFunc.nvl(desc_json.from_source);
        if (ComFunc.nvl(desc_json.fit_for) != "")
        {
            fit_for = ComFunc.nvl(desc_json.fit_for);
        }

        if (title == "")
        {
            return new
            {
                code = "failed",
                msg = "上传格式不正确,描述文件缺少插件名称"
            };
        }
        if (version == "" || !ICPVersion.IsICPVersion(version))
        {
            return new
            {
                code = "failed",
                msg = "上传格式不正确,描述文件缺少插件版本信息"
            };
        }
        if (depend_icp_version_min == "" || !ICPVersion.IsICPVersion(depend_icp_version_min))
        {
            return new
            {
                code = "failed",
                msg = "上传格式不正确,描述文件缺少最小依赖ICP版本信息"
            };
        }
        if (fit_for == "MIS")
        {
            if (depend_ui_version_min == "" || !ICPVersion.IsICPVersion(depend_ui_version_min))
            {
                return new
                {
                    code = "failed",
                    msg = "上传格式不正确,描述文件缺少最小依赖UI版本信息"
                };
            }
        }
        var his_version = ICPVersion.IsICPVersionThen(version);

        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        dynamic localinfo = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                             where t.title == title
                             select new
                             {
                                 uid = t.UID,
                                 plugin_no = t.Plugin_NO,
                                 title = t.Title,
                                 version = t.Version,
                                 icp_ver_max = t.ICP_Ver_Max,
                                 icp_ver_min = t.ICP_Ver_Min,
                                 ui_ver_max = t.UI_Ver_Max,
                                 ui_ver_min = t.UI_Ver_Min,
                                 his_uid = t.His_UID,
                                 is_load = t.Is_Load,
                                 from_source = t.From_Source
                             }).GetQueryList(metaup).FirstOrDefault();

        if (localinfo != null)
        {
            var localversion = new ICPVersion(ComFunc.nvl(localinfo.version));
            if (localversion >= his_version)
            {
                return new
                {
                    code = "failed",
                    msg = $"本地版本高于线上版本，本地版本-{localversion.ToString()},线上版本-{his_version.ToString()}"
                };
            }

            var rowcount = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                            select t).Count(metaup);
            DB.QuickInsert(metaup, "EXTEND_LOCALPLUGIN", new
            {
                UID = plugin_pk,
                Plugin_NO = $"Local{(rowcount + 1)}",
                Title = title,
                Version = his_version.ToString(),
                His_UID = "",
                Is_Load = 0,
                add_id = TokenPayLoad.ID,
                add_name = ComFunc.nvl(TokenPayLoad["name"]),
                add_ip = ClientInfo.IP,
                add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }
        else
        {
            var rowcount = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                            select t).Count(metaup);
            DB.QuickInsert(metaup, "EXTEND_LOCALPLUGIN", new
            {
                UID = plugin_pk,
                Plugin_NO = $"Local{(rowcount + 1)}",
                Title = title,
                Version = his_version.ToString(),
                His_UID = "",
                Is_Load = 0,
                add_id = TokenPayLoad.ID,
                add_name = ComFunc.nvl(TokenPayLoad["name"]),
                add_ip = ClientInfo.IP,
                add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }
        File.WriteAllBytes(Path.Combine(plugin_path, $"{his_version.ToString()}.zip"), filecontent);

        CommitTrans();
        return new
        {
            code = "success",
            msg = "上传成功"
        };
    }
    [EWRARunMode("Dev,Update")]
    [EWRARoute("delete", "/myplugins/{id}")]
    [EWRARouteDesc("插件列表-删除本地插件")]
    [EWRAAddInput("his_id", "string", "历史版本PK", "默认为当前最新版本", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息'
}")]
    public object DelPlugin(string id)
    {
        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        dynamic localinfo = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                             where t.UID == id
                             select new
                             {
                                 uid = t.UID,
                                 plugin_no = t.Plugin_NO,
                                 title = t.Title,
                                 version = t.Version,
                                 icp_ver_max = t.ICP_Ver_Max,
                                 icp_ver_min = t.ICP_Ver_Min,
                                 ui_ver_max = t.UI_Ver_Max,
                                 ui_ver_min = t.UI_Ver_Min,
                                 his_uid = t.His_UID,
                                 is_load = t.Is_Load,
                                 from_source = t.From_Source
                             }).GetQueryList(metaup).FirstOrDefault();
        if (localinfo == null)
        {
            return new
            {
                code = "failed",
                msg = "无该插件"
            };
        }
        if (BoolStd.IsNotBoolThen(localinfo.is_load))
        {
            return new
            {
                code = "failed",
                msg = "该插件已加载，请先卸载"
            };
        }
        var root_path = Path.GetFullPath(_down_root);
        var plugin_path = Path.Combine(root_path, localinfo.uid);
        if (Directory.Exists(plugin_path)) Directory.Delete(plugin_path, true);
        DB.QuickDelete(metaup, "EXTEND_LOCALPLUGIN", new
        {
            UID = localinfo.uid
        });
        CommitTrans();
        return new
        {
            code = "success",
            msg = "操作成功"
        };
    }

    [EWRARunMode("Dev,Update")]
    [EWRARoute("ws", "/myplugins/pack")]
    [EWRARouteDesc("将自己的插件打包")]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
}")]
    public object Pack()
    {
        var metaup = DB.NewMetaUnitParameter();
        //校验SystemSecretKey
        var key = WS.SendInputMsg("请输入系统运维密钥", 120);
        if (key != ComFunc.nvl(Configs["SystemSecretKey"]))
        {
            return new
            {
                code = "failed",
                msg = "系统运维密钥不正确，结束处理"
            };
        }
        //获取dll的列表
        var pluginlist = from t in Directory.GetFiles("Plugin", "*.dll", SearchOption.AllDirectories)
                         orderby Path.GetFileName(t)
                         select new
                         {
                             code = t,
                             value = Path.GetFileName(t)
                         };
        var selected_dlls = WS.SendMultiSelectMsgAndRead("请选择要导出的插件DLL", pluginlist, 120);
        //元数据结构
        var metalist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                        orderby t.MetaName
                        select new
                        {
                            t.MetaUID,
                            t.MetaName,
                            t.MetaDesc
                        }).GetQueryList(metaup);
        var metadata = from t in metalist
                       select new
                       {
                           code = t.MetaUID,
                           value = $"{t.MetaDesc}({t.MetaName})"
                       };
        var selected_metas = WS.SendMultiSelectMsgAndRead("请选择要导出的元数据", metadata, 120);
        //词典表
        var diclist = (from t in DB.LamdaTable(metaup, "EXTEND_DICTIONARY_TABLE", "a")
                       orderby t.DIC_Name
                       select new
                       {
                           t.DIC_UID,
                           t.DIC_Name,
                           t.DIC_Desc
                       }).GetQueryList(metaup);
        var dicdata = from t in diclist
                      select new
                      {
                          code = t.DIC_UID,
                          value = $"{t.DIC_Desc}({t.DIC_Name})"
                      };
        var selected_dics = WS.SendMultiSelectMsgAndRead("请选择要导出的词典表(包含数据)", dicdata, 120);

        //动态表单
        var dformlist = (from t in DB.LamdaTable(metaup, "EXTEND_DYNAMICFORM", "a")
                         orderby t.Name
                         select new
                         {
                             code = t.UID,
                             value = t.Name
                         }).GetQueryList(metaup);
        var selected_dforms = WS.SendMultiSelectMsgAndRead("请选择要导出的动态表单", dformlist, 120);
        //动态表单的事件
        var eventslist = (from t in DB.LamdaTable(metaup, "EXTEND_EVENTS4DFORM", "a")
                          orderby t.EventName
                          select new
                          {
                              code = t.EventNo,
                              value = t.EventName
                          }).GetQueryList(metaup);
        var selected_events = WS.SendMultiSelectMsgAndRead("请选择要导出的动态表单事件", eventslist, 120);

        //功能
        var functionlist = (from t in DB.LamdaTable(metaup, "EXTEND_FUNCTION", "a")
                            orderby t.FunctionName
                            select new
                            {
                                code = t.FunctionNo,
                                value = t.FunctionName
                            }).GetQueryList(metaup);
        var selected_functions = WS.SendMultiSelectMsgAndRead("请选择要导出的功能菜单", functionlist, 120);
        //角色与授权
        var rolelist = (from t in DB.LamdaTable(metaup, "EXTEND_ROLE", "a")
                        orderby t.RoleName
                        select new
                        {
                            code = t.RoleNo,
                            value = t.RoleName
                        }).GetQueryList(metaup);
        var selected_roles = WS.SendMultiSelectMsgAndRead("请选择要导出的角色", rolelist, 120);
        var selected_rolefunc = "";
        if (selected_roles != "")
        {
            var rolefunclist = (from t in DB.LamdaTable(metaup, "EXTEND_ROLE_FUNCTION", "a")
                                join t2 in DB.LamdaTable(metaup, "EXTEND_ROLE", "b") on t.RoleNo equals t2.RoleNo
                                join t3 in DB.LamdaTable(metaup, "EXTEND_FUNCTION", "c") on t.FunctionNo equals t3.FunctionNo
                                where t.RoleNo.within(selected_roles)
                                select new
                                {
                                    t.RoleNo,
                                    t.FunctionNo,
                                    t2.RoleName,
                                    t3.FunctionName
                                }).GetQueryList(metaup);
            var rolefuncdata = from t in rolefunclist
                               select new
                               {
                                   code = $"{t.RoleNo}|{t.FunctionNo}",
                                   value = $"{t.RoleName}-{t.FunctionName}"
                               };
            selected_rolefunc = WS.SendMultiSelectMsgAndRead("请选择要导出的功能授权设定", rolefuncdata, 120);
        }
        //配置档
        var selected_config_section = "";
        if (File.Exists(MyConfig.Configuration.ConfigFilePath))
        {
            var config = FrameDLRObject.IsJsonThen(File.ReadAllText(MyConfig.Configuration.ConfigFilePath), null, FrameDLRFlags.SensitiveCase);
            if (config != null)
            {
                var reserveKeys = new string[] { "Server", "WebSocket", "Setup", "View", "EFFC" }.Select(d => d.ToLower()).ToList();
                var config_sections = from t in config.Keys
                                      where !reserveKeys.Contains(t.ToLower())
                                      select new
                                      {
                                          code = t,
                                          value = t
                                      };

                selected_config_section = WS.SendMultiSelectMsgAndRead("请选择要导出的配置设定", config_sections, 120);
            }
        }
        //插件说明
        var memo = WS.SendTextMsgAndRead("请输入使用说明", null, 120);
        //插件名称
        var plugin_name = "";
        do
        {
            plugin_name = WS.SendInputMsg("请输入插件名称(必输)", 120);
        } while (plugin_name == "");
        //作者
        var author = WS.SendInputMsg("请输入作者", 120);
        //插件版本设定
        var version = WS.SendInputMsg("请输入版本号(不输入则默认为1.0.0)", 120);
        if (version == "") version = "1.0.0";
        //插件兼容ICP和UI设定
        var icp_ver_min = WS.SendInputMsg("请输入兼容ICP最低版本(不输入则为1.0.0)", 120);
        var icp_ver_max = WS.SendInputMsg("请输入兼容ICP最高版本(不输入则视为无上限)", 120);
        var ui_ver_min = WS.SendInputMsg("请输入兼容UI最低版本(不输入则为1.0.0)", 120);
        var ui_ver_max = WS.SendInputMsg("请输入兼容UI最高版本(不输入则视为无上限)", 120);

        if (icp_ver_min == "") icp_ver_min = "1.0.0";
        if (ui_ver_min == "") ui_ver_min = "1.0.0";
        //分目录
        var guid = Guid.NewGuid().ToString();
        var pack_root = Path.GetFullPath($"TempPlugins/Pack");
        var gen_root = $"{pack_root}/{guid}";
        if (!Directory.Exists(gen_root))
        {
            Directory.CreateDirectory(gen_root);
        }
        Directory.CreateDirectory($"{gen_root}/DLL");
        Directory.CreateDirectory($"{gen_root}/Meta");
        Directory.CreateDirectory($"{gen_root}/MetaData");
        Directory.CreateDirectory($"{gen_root}/Dictionary");
        Directory.CreateDirectory($"{gen_root}/DynamicForm");
        Directory.CreateDirectory($"{gen_root}/DynamicFormEvents");
        Directory.CreateDirectory($"{gen_root}/Function");
        Directory.CreateDirectory($"{gen_root}/Role");
        Directory.CreateDirectory($"{gen_root}/Auth");
        Directory.CreateDirectory($"{gen_root}/Config");

        //生成说明文件
        var plugin_desc = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
        plugin_desc.title = plugin_name;
        plugin_desc.description = memo;
        plugin_desc.version = version;
        plugin_desc.depend_icp_version_min = icp_ver_min;
        plugin_desc.depend_icp_version_max = icp_ver_max;
        plugin_desc.depend_ui_version_min = ui_ver_min;
        plugin_desc.depend_ui_version_max = ui_ver_max;
        plugin_desc.from_source = MyConfig.GetConfiguration("RDTPAPI", "System_ID");
        plugin_desc.fit_for = "MIS";

        var plugins = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
        plugin_desc.plugins = plugins;
        #region 根据输入项生成各种文件
        var progress_max = 10;
        var index = 0;
        WS.SendProgressBarMsg("执行生成操作", index++, 0, progress_max);
        //DLL
        if (selected_dlls != "")
        {
            foreach (var f in selected_dlls.Split(",", StringSplitOptions.RemoveEmptyEntries))
            {
                File.Copy(f, $"{gen_root}/DLL/{Path.GetFileName(f)}", true);
            }
            plugins.dll = selected_dlls.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(d => Path.GetFileName(d)).ToArray();
        }
        WS.SendProgressBarMsg("执行生成操作-DLL完成", index++, 0, progress_max);
        //元数据结构
        if (selected_metas != "")
        {
            var postdata = FrameDLRObject.CreateInstance();
            postdata.ids = selected_metas;
            dynamic result = FrameDLRObject.CreateInstance(CallLocalLogic("/metadata/export_scripts", "Patch", null, null, postdata, false));
            if (result.code != "success")
            {
                return result;
            }

            var metacontent = ComFunc.Base64DeCode(result.file);
            File.WriteAllText($"{gen_root}/Meta/{result.filename}", metacontent);
            plugins.meta = new
            {
                data_ids = selected_metas,
                files = new string[] { result.filename }
            };

        }
        WS.SendProgressBarMsg("执行生成操作-元数据完成", index++, 0, progress_max);

        //动态表单
        if (selected_dforms != "")
        {
            var postdata = FrameDLRObject.CreateInstance();
            postdata.ids = selected_dforms;
            dynamic result = FrameDLRObject.CreateInstance(CallLocalLogic("/d_form/script/export", "Patch", null, null, postdata, false));
            if (result.code != "success")
            {
                return result;
            }

            var metacontent = ComFunc.Base64DeCode(result.file);
            File.WriteAllText($"{gen_root}/DynamicForm/{result.filename}", metacontent);
            plugins.dynamic_form = new
            {
                data_ids = selected_dforms,
                files = new string[] { result.filename }
            };
        }
        WS.SendProgressBarMsg("执行生成操作-动态表单完成", index++, 0, progress_max);
        //词典表
        if (selected_dics != "")
        {
            var postdata = FrameDLRObject.CreateInstance();
            postdata.ids = selected_dics;
            dynamic result = FrameDLRObject.CreateInstance(CallLocalLogic("/dictionarytable/script/export", "Patch", null, null, postdata, false));
            if (result.code != "success")
            {
                return result;
            }

            var metacontent = ComFunc.Base64DeCode(result.file);
            File.WriteAllText($"{gen_root}/Dictionary/{result.filename}", metacontent);
            plugins.dictionary = new
            {
                data_ids = selected_dics,
                files = new string[] { result.filename }
            };
        }
        WS.SendProgressBarMsg("执行生成操作-词典表完成", index++, 0, progress_max);
        //动态表单事件
        if (selected_events != "")
        {
            var postdata = FrameDLRObject.CreateInstance();
            postdata.nos = selected_events;
            dynamic result = FrameDLRObject.CreateInstance(CallLocalLogic("/events4dform/script/export", "Patch", null, null, postdata, false));
            if (result.code != "success")
            {
                return result;
            }

            var metacontent = ComFunc.Base64DeCode(result.file);
            File.WriteAllText($"{gen_root}/DynamicFormEvents/{result.filename}", metacontent);
            plugins.dynamic_events = new
            {
                data_ids = selected_events,
                files = new string[] { result.filename }
            };
        }
        WS.SendProgressBarMsg("执行生成操作-动态表单完成", index++, 0, progress_max);
        //功能菜单
        if (selected_functions != "")
        {
            var arr = selected_functions.Split(",", StringSplitOptions.RemoveEmptyEntries);
            var datalist = (from t in DB.LamdaTable(metaup, "EXTEND_FUNCTION", "a")
                                //where t.FunctionNo.within(selected_functions)
                            select t).GetQueryList(metaup);
            var selectedlist = from t in datalist
                               where arr.Contains((string)ComFunc.nvl(t.FunctionNo))
                               select t;
            var list = new List<FrameDLRObject>();
            list.AddRange(selectedlist);
            var p_function_no = selectedlist.Where(w => ComFunc.nvl(w.P_FunctionNo) != "").Select(d => ComFunc.nvl(d.GetValue("P_FunctionNo"))).ToArray();
            List<FrameDLRObject> p_list = null;
            while (p_function_no.Length > 0)
            {
                p_list = datalist.Where(w => p_function_no.Contains((string)w.FunctionNo)).ToList();
                list.AddRange(p_list);
                p_function_no = p_list.Where(w => ComFunc.nvl(w.P_FunctionNo) != "").Select(d => ComFunc.nvl(d.GetValue("P_FunctionNo"))).ToArray();
            }


            var fobj = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
            fobj.table = "EXTEND_FUNCTION";
            fobj.data = list.Select(d =>
            {
                d.add_time = DateTimeStd.IsDateTimeThen(d.add_time, "yyyy-MM-dd HH:mm:ss");
                d.last_time = DateTimeStd.IsDateTimeThen(d.add_time, "yyyy-MM-dd HH:mm:ss");
                d.Is_Menu = BoolStd.ConvertTo(d.Is_Menu, 1, 0);
                return d;
            });
            fobj.pk = new string[] { "FunctionNo" };

            var func_file_name = "Extend_Function.json";
            File.WriteAllText($"{gen_root}/Function/{func_file_name}", fobj.tojsonstring());
            selected_functions = string.Join(",", list.Select(d => ComFunc.nvl(d.GetValue("FunctionNo"))).ToArray());
            plugins.function = new
            {
                data_ids = selected_functions,
                files = new string[] { func_file_name }
            };

        }
        WS.SendProgressBarMsg("执行生成操作-功能菜单完成", index++, 0, progress_max);
        //角色
        if (selected_roles != "")
        {
            var datalist = (from t in DB.LamdaTable(metaup, "EXTEND_ROLE", "a")
                            where t.RoleNo.within(selected_roles)
                            select t).GetQueryList(metaup);
            var fobj = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
            fobj.table = "EXTEND_ROLE";
            fobj.data = datalist.Select(d =>
            {
                d.add_time = DateTimeStd.IsDateTimeThen(d.add_time, "yyyy-MM-dd HH:mm:ss");
                d.last_time = DateTimeStd.IsDateTimeThen(d.add_time, "yyyy-MM-dd HH:mm:ss");
                return d;
            });
            fobj.pk = new string[] { "RoleNo" };

            var role_file_name = "EXTEND_ROLE.json";
            File.WriteAllText($"{gen_root}/Role/{role_file_name}", fobj.tojsonstring());
            plugins.role = new
            {
                data_ids = selected_roles,
                files = new string[] { role_file_name }
            };
        }
        WS.SendProgressBarMsg("执行生成操作-角色完成", index++, 0, progress_max);
        //角色授权
        if (selected_rolefunc != "")
        {
            var datalist = (from t in DB.LamdaTable(metaup, "EXTEND_ROLE_FUNCTION", "a")
                            select t).GetQueryList(metaup);
            var fobj = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
            fobj.table = "EXTEND_ROLE_FUNCTION";
            var rolefunc_arr = selected_rolefunc.Split(",", StringSplitOptions.RemoveEmptyEntries);
            fobj.data = datalist.Where(w => rolefunc_arr.Contains($"{w.RoleNo}|{w.FunctionNo}")).Select(d =>
            {
                d.add_time = DateTimeStd.IsDateTimeThen(d.add_time, "yyyy-MM-dd HH:mm:ss");
                d.last_time = DateTimeStd.IsDateTimeThen(d.add_time, "yyyy-MM-dd HH:mm:ss");
                return d;
            });
            fobj.pk = new string[] { "RoleNo", "FunctionNo" };

            var rf_file_name = "EXTEND_ROLE_FUNCTION.json";
            File.WriteAllText($"{gen_root}/Auth/{rf_file_name}", fobj.tojsonstring());
            plugins.auth = new
            {
                data_ids = selected_rolefunc,
                files = new string[] { rf_file_name }
            };
        }
        WS.SendProgressBarMsg("执行生成操作-角色授权完成", index++, 0, progress_max);
        //Config
        if (selected_config_section != "")
        {
            var arr = selected_config_section.Split(",", StringSplitOptions.RemoveEmptyEntries);
            var config = FrameDLRObject.IsJsonThen(File.ReadAllText(MyConfig.Configuration.ConfigFilePath), null, FrameDLRFlags.SensitiveCase);
            foreach (var k in config.Keys)
            {
                if (!arr.Contains(k))
                {
                    config.Remove(k);
                }
                else
                {
                    var items = (FrameDLRObject)config.GetValue(k);
                    foreach (var kk in items.Keys)
                    {
                        items.SetValue(kk, "");
                    }
                }
            }
            var c_file_name = "Config.json";
            File.WriteAllText($"{gen_root}/Config/{c_file_name}", config.ToJSONString());
            plugins.config = new
            {
                data_ids = selected_config_section,
                files = new string[] { c_file_name }
            };
        }
        WS.SendProgressBarMsg("执行生成操作-Config完成", index++, 0, progress_max);
        #endregion
        File.WriteAllText($"{gen_root}/_plugin_desc.json", plugin_desc.tojsonstring());
        //打包
        var tozippath = $"{pack_root}/{guid}.zip";
        CompressReturnFileName(tozippath, gen_root);
        WS.SendProgressBarMsg("执行生成操作-打包完成", index++, 0, progress_max);
        //下载
        var dl_success = WS.SendFile($"{plugin_name}.zip", File.ReadAllBytes(tozippath));
        Directory.Delete(gen_root, true);
        File.Delete(tozippath);
        if (!dl_success)
        {
            return new
            {
                code = "failed",
                msg = "下载文件失败"
            };
        }

        return new
        {
            code = "success",
            msg = "操作成功"
        };
    }

    [EWRARunMode("Dev,Update")]
    [EWRARoute("ws", "/myplugins/load")]
    [EWRARouteDesc("加载下载的插件")]
    [EWRAAddInput("id", "string", "插件UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
}")]
    public object Load()
    {
        var id = ComFunc.nvl(QueryStringD.id);
        //校验SystemSecretKey
        var key = WS.SendInputMsg("请输入系统运维密钥", 120);
        if (key != ComFunc.nvl(Configs["SystemSecretKey"]))
        {
            return new
            {
                code = "failed",
                msg = "系统运维密钥不正确，结束处理"
            };
        }
        var metaup = DB.NewMetaUnitParameter();
        if (id == "")
        {
            var list = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                        where t.Is_Load != 1
                        select new
                        {
                            uid = t.UID,
                            plugin_no = t.Plugin_NO,
                            title = t.Title,
                        }).GetQueryList(metaup);
            var datalist = from t in list
                           select new
                           {
                               code = t.uid,
                               value = $"{t.plugin_no}({t.title})"
                           };

            id = WS.SendSelectMsgAndRead($"请选择要加载的插件(必输)", datalist, 120);
            if (id == "")
            {
                return new
                {
                    code = "failed",
                    msg = "用户未选择插件，取消操作"
                };
            }
        }

        dynamic localinfo = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                             where t.UID == id
                             select new
                             {
                                 uid = t.UID,
                                 plugin_no = t.Plugin_NO,
                                 title = t.Title,
                                 version = t.Version,
                                 icp_ver_max = t.ICP_Ver_Max,
                                 icp_ver_min = t.ICP_Ver_Min,
                                 ui_ver_max = t.UI_Ver_Max,
                                 ui_ver_min = t.UI_Ver_Min,
                                 his_uid = t.His_UID,
                                 is_load = t.Is_Load,
                                 from_source = t.From_Source
                             }).GetQueryList(metaup).FirstOrDefault();
        if (localinfo == null)
        {
            return new
            {
                code = "failed",
                msg = "无该插件"
            };
        }
        if (BoolStd.IsNotBoolThen(localinfo.is_load))
        {
            return new
            {
                code = "failed",
                msg = "该插件已加载"
            };
        }
        var root_path = Path.GetFullPath(_down_root);
        var plugin_path = Path.Combine(root_path, localinfo.uid);
        if (!Directory.Exists(plugin_path))
        {
            return new
            {
                code = "failed",
                msg = "插件目录不存在"
            };
        }
        var filepath = Path.Combine(plugin_path, $"{localinfo.version}.zip");
        if (!File.Exists(filepath)) return new
        {
            code = "failed",
            msg = "插件不存在"
        };
        var zip_path = Path.Combine(plugin_path, $"{localinfo.version}");
        UnzipFile(filepath, zip_path);

        dynamic plugin_desc = FrameDLRObject.IsJsonThen(File.ReadAllText($"{zip_path}/_plugin_desc.json", Encoding.UTF8));
        if (plugin_desc == null)
        {
            return new
            {
                code = "failed",
                msg = "缺少插件描述文件"
            };
        }
        //检查插件兼容版本
        var icp_version_min = new ICPVersion(ComFunc.nvl(plugin_desc.depend_icp_version_min));
        var icp_version_max = ICPVersion.IsICPVersionThen(ComFunc.nvl(plugin_desc.depend_icp_version_max));
        var ui_version_min = new ICPVersion(ComFunc.nvl(plugin_desc.depend_ui_version_min));
        var ui_version_max = ICPVersion.IsICPVersionThen(ComFunc.nvl(plugin_desc.depend_ui_version_max));
        var system_version = ICPSystemVersion.CurrentVersion;
        if (system_version.ICPVersion < icp_version_min)
        {
            return new
            {
                code = "failed",
                msg = $"当前系统ICP版本与插件版本不兼容"
            };
        }
        if (icp_version_max != null && system_version.ICPVersion > icp_version_max)
        {
            return new
            {
                code = "failed",
                msg = "当前系统ICP版本与插件版本不兼容"
            };
        }
        if (plugin_desc.plugins == null)
        {
            return new
            {
                code = "failed",
                msg = "描述文件中" +
                "缺少plugins信息"
            };
        }

        var progress_max = 9;
        var progress_index = 0;
        WS.SendProgressBarMsg("执行加载操作，请不要关闭对话框", progress_index++, 0, progress_max);
        #region DLL
        var header = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
        header.SystemSecretKey = key;
        if (plugin_desc.plugins.dll != null)
        {
            //卸载当前运行的插件
            if (!BoolStd.IsNotBoolThen(WS.SendConfirmMsgAndRead("加载插件需要先停止当前已经加载运行中的插件，确认停止吗?", 120)))
            {
                return new
                {
                    code = "failed",
                    msg = "用户终止操作"
                };
            }

            var result = "";
            var to_plugin_path = Path.GetFullPath("Plugin");
            var dlls = ((IEnumerable<object>)plugin_desc.plugins.dll).Select(d => ComFunc.nvl(d));
            //EFFC 3.5.3是基于core 2.x构建，不具备动态卸载Assembly的能力
            if (system_version.EFFCVersion > new ICPVersion("3.5.3"))
            {
                result = ComFunc.nvl(CallLocalLogic("/_plugin/unload", "POST", header));
                if (result != "操作成功")
                {
                    return new
                    {
                        code = "failed",
                        msg = $"停止插件运行失败"
                    };
                }
                foreach (var f in dlls)
                {
                    var t_path = Path.Combine(to_plugin_path, f);
                    var err_msg = "";
                    if (!ComFunc.TryCopyFile(Path.Combine(zip_path, $"Dll/{f}"), t_path, true, ref err_msg))
                    {
                        var msg = $"文件{f}无法复制({err_msg})，请在停止服务之后删除{to_plugin_path}下的{f}文件，然后再执行加载操作";
                        WS.SendAlertMsg(msg);
                        WS.SendConsoleMsg($"注意：{msg}");
                    }
                }
            }
            else
            {
                foreach (var f in dlls)
                {
                    var t_path = Path.Combine(to_plugin_path, f);
                    if (File.Exists(t_path))
                    {
                        if (!BoolStd.IsNotBoolThen(WS.SendConfirmMsgAndRead($"检测到已存在{f}文件，是否忽略并继续?", 120)))
                        {
                            return new
                            {
                                code = "failed",
                                msg = $"用户终止操作！如果要继续加载，请先停止服务，删除该文件后再继续执行加载操作"
                            };
                        }
                        else
                        {
                            continue;
                        }
                    }
                    File.Copy(Path.Combine(zip_path, $"Dll/{f}"), t_path);
                }
            }
        }
        WS.SendProgressBarMsg("执行加载操作-DLL完成", progress_index++, 0, progress_max);
        #endregion
        #region 元数据
        if (plugin_desc.plugins.meta != null)
        {
            var files = ((IEnumerable<object>)plugin_desc.plugins.meta.files).Select(d => ComFunc.nvl(d));
            foreach (var f in files)
            {
                var path = Path.Combine(zip_path, $"Meta/{f}");
                var content = File.ReadAllText(path);
                var re = CallLocalLogic("/metadata/import_scripts", "Patch", null, null,
                    FrameDLRObject.CreateInstance(new
                    {
                        data = ComFunc.ToJson(new
                        {
                            filetype = ResponseHeader_ContentType.json,
                            filename = f,
                            filelength = Encoding.UTF8.GetByteCount(content),
                            file = ComFunc.Base64Code(content)
                        })
                    }));
                var result_meta = FrameDLRObject.CreateInstance(re);
                if (result_meta.code != "success")
                {
                    return result_meta;
                }
            }
        }
        WS.SendProgressBarMsg("执行加载操作-元数据完成", progress_index++, 0, progress_max);
        #endregion
        #region 动态表单
        if (plugin_desc.plugins.dynamic_form != null)
        {
            var files = ((IEnumerable<object>)plugin_desc.plugins.dynamic_form.files).Select(d => ComFunc.nvl(d));
            foreach (var f in files)
            {
                var path = Path.Combine(zip_path, $"DynamicForm/{f}");
                string content = File.ReadAllText(path);
                var result_meta = FrameDLRObject.CreateInstance(CallLocalLogic("/d_form/script/import", "Patch", null, null,
                    FrameDLRObject.CreateInstance(new
                    {
                        data = ComFunc.ToJson(new
                        {
                            filetype = ResponseHeader_ContentType.json,
                            filename = f,
                            filelength = Encoding.UTF8.GetByteCount(content),
                            file = ComFunc.Base64Code(content)
                        })
                    })));
                if (result_meta.code != "success")
                {
                    return result_meta;
                }
            }
        }
        WS.SendProgressBarMsg("执行加载操作-动态表单完成", progress_index++, 0, progress_max);
        #endregion
        #region 词典表
        if (plugin_desc.plugins.dictionary != null)
        {
            var files = ((IEnumerable<object>)plugin_desc.plugins.dictionary.files).Select(d => ComFunc.nvl(d));
            foreach (var f in files)
            {
                var path = Path.Combine(zip_path, $"Dictionary/{f}");
                string content = File.ReadAllText(path);
                var result_meta = FrameDLRObject.CreateInstance(CallLocalLogic("/dictionarytable/script/import", "Patch", null, null,
                    FrameDLRObject.CreateInstance(new
                    {
                        data = ComFunc.ToJson(new
                        {
                            filetype = ResponseHeader_ContentType.json,
                            filename = f,
                            filelength = Encoding.UTF8.GetByteCount(content),
                            file = ComFunc.Base64Code(content)
                        })
                    })));
                if (result_meta.code != "success")
                {
                    return result_meta;
                }
            }
        }
        WS.SendProgressBarMsg("执行加载操作-词典表完成", progress_index++, 0, progress_max);
        #endregion
        #region 动态表单的事件
        if (plugin_desc.plugins.dynamic_events != null)
        {
            var files = ((IEnumerable<object>)plugin_desc.plugins.dynamic_events.files).Select(d => ComFunc.nvl(d));
            foreach (var f in files)
            {
                var path = Path.Combine(zip_path, $"DynamicFormEvents/{f}");
                string content = File.ReadAllText(path);
                var result_meta = FrameDLRObject.CreateInstance(CallLocalLogic("/events4dform/script/import", "Patch", null, null,
                    FrameDLRObject.CreateInstance(new
                    {
                        data = ComFunc.ToJson(new
                        {
                            filetype = ResponseHeader_ContentType.json,
                            filename = f,
                            filelength = Encoding.UTF8.GetByteCount(content),
                            file = ComFunc.Base64Code(content)
                        })
                    })));
                if (result_meta.code != "success")
                {
                    return result_meta;
                }
            }
        }
        WS.SendProgressBarMsg("执行加载操作-动态表单事件完成", progress_index++, 0, progress_max);
        #endregion
        #region 功能
        if (plugin_desc.plugins.function != null)
        {
            var files = ((IEnumerable<object>)plugin_desc.plugins.function.files).Select(d => ComFunc.nvl(d));
            foreach (var f in files)
            {
                var path = Path.Combine(zip_path, $"Function/{f}");
                string content = File.ReadAllText(path);
                using (var dobj = FrameDLRObject.IsJsonThen(content, (FrameDLRObject)FrameDLRObject.CreateInstance(), EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase))
                {
                    var tablename = ComFunc.nvl(dobj.GetValue("table"));
                    var data = (IEnumerable<object>)dobj.GetValue("data");
                    var pk = (IEnumerable<object>)dobj.GetValue("pk");
                    foreach (FrameDLRObject item in data)
                    {
                        FrameDLRObject w = FrameDLRObject.CreateInstance();
                        foreach (string s in pk)
                        {
                            w.SetValue(s, item.GetValue(s));
                        }
                        DB.QuickDelete(metaup, tablename, w);
                        DB.QuickInsert(metaup, tablename, item);
                    }
                }
            }
        }
        WS.SendProgressBarMsg("执行加载操作-功能菜单完成", progress_index++, 0, progress_max);
        #endregion
        #region 角色
        if (plugin_desc.plugins.role != null)
        {
            var files = ((IEnumerable<object>)plugin_desc.plugins.role.files).Select(d => ComFunc.nvl(d));
            foreach (var f in files)
            {
                var path = Path.Combine(zip_path, $"Role/{f}");
                string content = File.ReadAllText(path);
                using (var dobj = FrameDLRObject.IsJsonThen(content, (FrameDLRObject)FrameDLRObject.CreateInstance(), EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase))
                {
                    var tablename = ComFunc.nvl(dobj.GetValue("table"));
                    var data = (IEnumerable<object>)dobj.GetValue("data");
                    var pk = (IEnumerable<object>)dobj.GetValue("pk");
                    foreach (FrameDLRObject item in data)
                    {
                        FrameDLRObject w = FrameDLRObject.CreateInstance();
                        foreach (string s in pk)
                        {
                            w.SetValue(s, item.GetValue(s));
                        }
                        DB.QuickDelete(metaup, tablename, w);
                        DB.QuickInsert(metaup, tablename, item);
                    }
                }
            }
        }
        WS.SendProgressBarMsg("执行加载操作-角色完成", progress_index++, 0, progress_max);
        #endregion
        #region 角色授权
        if (plugin_desc.plugins.auth != null)
        {
            var files = ((IEnumerable<object>)plugin_desc.plugins.auth.files).Select(d => ComFunc.nvl(d));
            foreach (var f in files)
            {
                var path = Path.Combine(zip_path, $"Auth/{f}");
                string content = File.ReadAllText(path);
                using (var dobj = FrameDLRObject.IsJsonThen(content, (FrameDLRObject)FrameDLRObject.CreateInstance(), EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase))
                {
                    var tablename = ComFunc.nvl(dobj.GetValue("table"));
                    var data = (IEnumerable<object>)dobj.GetValue("data");
                    var pk = (IEnumerable<object>)dobj.GetValue("pk");
                    foreach (FrameDLRObject item in data)
                    {
                        FrameDLRObject w = FrameDLRObject.CreateInstance();
                        foreach (string s in pk)
                        {
                            w.SetValue(s, item.GetValue(s));
                        }
                        DB.QuickDelete(metaup, tablename, w);
                        DB.QuickInsert(metaup, tablename, item);
                    }
                }
            }
        }
        WS.SendProgressBarMsg("执行加载操作-角色完成", progress_index++, 0, progress_max);
        #endregion
        #region 配置档
        if (plugin_desc.plugins.config != null)
        {
            var config = FrameDLRObject.IsJsonThen(File.ReadAllText(MyConfig.Configuration.ConfigFilePath), null, FrameDLRFlags.SensitiveCase);
            var files = ((IEnumerable<object>)plugin_desc.plugins.config.files).Select(d => ComFunc.nvl(d));
            foreach (var f in files)
            {
                var path = Path.Combine(zip_path, $"Config/{f}");
                string content = File.ReadAllText(path);
                var dobj = FrameDLRObject.IsJsonThen(content, null, FrameDLRFlags.SensitiveCase);
                if (dobj != null)
                {
                    foreach (var k in dobj.Keys)
                    {
                        if (!config.Keys.Contains(k))
                        {
                            if (dobj.GetValue(k) is FrameDLRObject)
                            {
                                var innerobj = (FrameDLRObject)dobj.GetValue(k);
                                foreach (var ik in innerobj.Keys)
                                {
                                    var newvalue = WS.SendInputMsg($"请输入配置项{k}.{ik}的值（当前默认为{(ComFunc.nvl(innerobj.GetValue(ik)) == "" ? "空" : ComFunc.nvl(innerobj.GetValue(ik)))}）：", 120);
                                    innerobj.SetValue(ik, newvalue);
                                }
                                config.SetValue(k, innerobj);
                            }
                            else
                            {
                                var newvalue = WS.SendInputMsg($"请输入配置项{k}的值（当前默认为{(ComFunc.nvl(dobj.GetValue(k)) == "" ? "空" : ComFunc.nvl(dobj.GetValue(k)))}）：", 120);
                                config.SetValue(k, newvalue);
                            }

                        }
                    }
                }
            }
            MyConfig.Configuration.WriteConfigs(config.ToJSONString());
            MyConfig.Configuration.Reload();
        }
        WS.SendProgressBarMsg("执行加载操作-配置档完成", progress_index++, 0, progress_max);
        #endregion
        //启用插件
        var result_load = ComFunc.nvl(CallLocalLogic("/_plugin/load", "POST", header));
        if (result_load != "操作成功")
        {
            return new
            {
                code = "failed",
                msg = $"启用插件运行失败"
            };
        }
        Directory.Delete(zip_path, true);
        DB.QuickUpdate(metaup, "EXTEND_LOCALPLUGIN", new
        {
            Is_Load = 1
        }, new
        {
            localinfo.UID
        });
        return new
        {
            code = "success",
            msg = "操作成功"
        };
    }
    [EWRARunMode("Dev,Update")]
    [EWRARoute("ws", "/myplugins/unload")]
    [EWRAAddInput("id", "string", "插件UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRARouteDesc("加载下载的插件")]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
}")]
    public object Unload()
    {
        var id = ComFunc.nvl(QueryStringD.id);
        //校验SystemSecretKey
        var key = WS.SendInputMsg("请输入系统运维密钥", 120);
        if (key != ComFunc.nvl(Configs["SystemSecretKey"]))
        {
            return new
            {
                code = "failed",
                msg = "系统运维密钥不正确，结束处理"
            };
        }
        if (!BoolStd.IsNotBoolThen(WS.SendConfirmMsgAndRead("确认要卸载插件吗,卸载会导致系统数据删除,确认要删除吗?", 120)))
        {
            return new
            {
                code = "failed",
                msg = "用户终止操作，结束处理"
            };
        }
        var metaup = DB.NewMetaUnitParameter();
        if (id == "")
        {
            var list = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                        where t.Is_Load == 1
                        select new
                        {
                            uid = t.UID,
                            plugin_no = t.Plugin_NO,
                            title = t.Title,
                        }).GetQueryList(metaup);
            var datalist = from t in list
                           select new
                           {
                               code = t.uid,
                               value = $"{t.plugin_no}({t.title})"
                           };

            id = WS.SendSelectMsgAndRead($"请选择要卸载的插件(必输)", datalist, 120);
            if (id == "")
            {
                return new
                {
                    code = "failed",
                    msg = "用户未选择插件，取消操作"
                };
            }
        }

        dynamic localinfo = (from t in DB.LamdaTable(metaup, "EXTEND_LOCALPLUGIN", "a")
                             where t.UID == id
                             select new
                             {
                                 uid = t.UID,
                                 plugin_no = t.Plugin_NO,
                                 title = t.Title,
                                 version = t.Version,
                                 icp_ver_max = t.ICP_Ver_Max,
                                 icp_ver_min = t.ICP_Ver_Min,
                                 ui_ver_max = t.UI_Ver_Max,
                                 ui_ver_min = t.UI_Ver_Min,
                                 his_uid = t.His_UID,
                                 is_load = t.Is_Load,
                                 from_source = t.From_Source
                             }).GetQueryList(metaup).FirstOrDefault();
        if (localinfo == null)
        {
            return new
            {
                code = "failed",
                msg = "无该插件"
            };
        }
        if (!BoolStd.IsNotBoolThen(localinfo.is_load))
        {
            return new
            {
                code = "failed",
                msg = "该插件已经卸载"
            };
        }
        var root_path = Path.GetFullPath(_down_root);
        var plugin_path = Path.Combine(root_path, localinfo.uid);
        if (!Directory.Exists(plugin_path))
        {
            return new
            {
                code = "failed",
                msg = "插件目录不存在"
            };
        }
        var filepath = Path.Combine(plugin_path, $"{localinfo.version}.zip");
        if (!File.Exists(filepath)) return new
        {
            code = "failed",
            msg = "插件不存在"
        };
        var zip_path = Path.Combine(plugin_path, $"{localinfo.version}");
        UnzipFile(filepath, zip_path);
        var system_version = ICPSystemVersion.CurrentVersion;
        dynamic plugin_desc = FrameDLRObject.IsJsonThen(File.ReadAllText($"{zip_path}/_plugin_desc.json", Encoding.UTF8));
        if (plugin_desc == null)
        {
            return new
            {
                code = "failed",
                msg = "缺少插件描述文件"
            };
        }
        var progress_max = 8;
        var progress_index = 0;
        WS.SendProgressBarMsg("执行卸载操作，请不要关闭对话框", progress_index++, 0, progress_max);
        #region DLL
        var header = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
        header.SystemSecretKey = key;
        if (plugin_desc.plugins.dll != null)
        {
            //卸载当前运行的插件
            if (!BoolStd.IsNotBoolThen(WS.SendConfirmMsgAndRead("加载插件需要先停止当前已经加载运行中的插件，确认停止吗?", 120)))
            {
                return new
                {
                    code = "failed",
                    msg = "用户终止操作"
                };
            }

            var result = "";
            var to_plugin_path = Path.GetFullPath("Plugin");
            var dlls = ((IEnumerable<object>)plugin_desc.plugins.dll).Select(d => ComFunc.nvl(d));
            result = ComFunc.nvl(CallLocalLogic("/_plugin/unload", "POST", header));
            if (result != "操作成功")
            {
                return new
                {
                    code = "failed",
                    msg = $"停止插件运行失败"
                };
            }
            //EFFC 3.5.3是基于core 2.x构建，不具备动态卸载Assembly的能力
            if (system_version.EFFCVersion > new ICPVersion("3.5.3"))
            {
                foreach (var f in dlls)
                {
                    var t_path = Path.Combine(to_plugin_path, f);
                    if (File.Exists(t_path))
                    {
                        var error_msg = "";
                        if (!ComFunc.TryDeleteFile(t_path, ref error_msg))
                        {
                            var msg = $"文件{f}无法删除({error_msg})，可以在停止服务之后删除{to_plugin_path}下的{f}文件";
                            WS.SendAlertMsg(msg);
                            WS.SendConsoleMsg($"注意：{msg}");
                        }
                    }
                }
            }
            else
            {
                var msg = $"所有插件API都已经卸载，要完成卸载DLL操作，请先停止服务，删除{to_plugin_path}下的{string.Join(",", dlls.ToArray())}该后再重启API服务即可";
                WS.SendAlertMsg(msg);
                WS.SendConsoleMsg($"注意：{msg}");
            }
        }
        WS.SendProgressBarMsg("执行卸载操作-DLL完成", progress_index++, 0, progress_max);
        #endregion
        #region 元数据
        if (plugin_desc.plugins.meta != null)
        {
            var ids = ((string)ComFunc.nvl(plugin_desc.plugins.meta.data_ids)).Split(",");
            foreach (var s in ids)
            {
                var re = FrameDLRObject.CreateInstance(CallLocalLogic($"/metadata/{s}/unlock", "Patch"));
                //if (re.code != "success")
                //{
                //    return re;
                //}
                re = CallLocalLogic($"/metadata/{s}", "Delete");
            }
        }
        WS.SendProgressBarMsg("执行卸载操作-元数据完成", progress_index++, 0, progress_max);
        #endregion
        #region 动态表单
        if (plugin_desc.plugins.dynamic_form != null)
        {
            var ids = ((string)ComFunc.nvl(plugin_desc.plugins.dynamic_form.data_ids)).Split(",");
            foreach (var s in ids)
            {
                var re = FrameDLRObject.CreateInstance(CallLocalLogic($"/d_form/{s}", "Delete"));
                //if (re.code != "success")
                //{
                //    return re;
                //}
            }
        }
        WS.SendProgressBarMsg("执行卸载操作-动态表单完成", progress_index++, 0, progress_max);
        #endregion
        #region 词典表
        if (plugin_desc.plugins.dictionary != null)
        {
            var ids = ((string)ComFunc.nvl(plugin_desc.plugins.dictionary.data_ids)).Split(",");
            foreach (var s in ids)
            {
                var re = FrameDLRObject.CreateInstance(CallLocalLogic($"/dictionarytable/{s}/unlock", "Patch"));
                re = CallLocalLogic($"/dictionarytable/{s}", "Delete");
            }
        }
        WS.SendProgressBarMsg("执行卸载操作-词典表完成", progress_index++, 0, progress_max);
        #endregion
        #region 动态表单的事件
        if (plugin_desc.plugins.dynamic_events != null)
        {
            var ids = ((string)ComFunc.nvl(plugin_desc.plugins.dynamic_events.data_ids)).Split(",");
            foreach (var s in ids)
            {
                var re = CallLocalLogic($"/events4dform/{s}", "Delete");
            }
        }
        WS.SendProgressBarMsg("执行卸载操作-动态表单事件完成", progress_index++, 0, progress_max);
        #endregion
        #region 功能
        if (plugin_desc.plugins.function != null)
        {
            var ids = ((string)ComFunc.nvl(plugin_desc.plugins.function.data_ids)).Split(",");
            foreach (var s in ids)
            {
                var re = CallLocalLogic($"/function/{s}", "Delete");
            }
        }
        WS.SendProgressBarMsg("执行卸载操作-功能菜单完成", progress_index++, 0, progress_max);
        #endregion
        #region 角色
        if (plugin_desc.plugins.role != null)
        {
            var ids = ((string)ComFunc.nvl(plugin_desc.plugins.role.data_ids)).Split(",");
            foreach (var s in ids)
            {
                //超级管理员角色不可删除
                if (s == "R999") continue;
                var re = CallLocalLogic($"/role/{s}", "Delete");
            }
        }
        WS.SendProgressBarMsg("执行卸载操作-角色完成", progress_index++, 0, progress_max);
        #endregion
        #region 配置档
        if (plugin_desc.plugins.config != null)
        {
            var config = FrameDLRObject.IsJsonThen(File.ReadAllText(MyConfig.Configuration.ConfigFilePath), null, FrameDLRFlags.SensitiveCase);
            var ids = ((string)ComFunc.nvl(plugin_desc.plugins.config.data_ids)).Split(",");
            foreach (var s in ids)
            {
                //超级管理员角色不可删除
                config.Remove(s);
            }
            MyConfig.Configuration.WriteConfigs(config.ToJSONString());
            MyConfig.Configuration.Reload();
        }
        WS.SendProgressBarMsg("执行卸载操作-配置档完成", progress_index++, 0, progress_max);
        #endregion

        //启用插件
        var result_load = ComFunc.nvl(CallLocalLogic("/_plugin/load", "POST", header));
        if (result_load != "操作成功")
        {
            return new
            {
                code = "failed",
                msg = $"启用插件运行失败"
            };
        }
        Directory.Delete(zip_path, true);
        DB.QuickUpdate(metaup, "EXTEND_LOCALPLUGIN", new
        {
            Is_Load = 0
        }, new
        {
            localinfo.UID
        });
        return new
        {
            code = "success",
            msg = "操作成功"
        };
    }

    public string CompressReturnFileName(string toZipFilePath, string fromFilePath, params string[] otherFiles)
    {
        ZipArchive zipArchive = null;
        var path = Path.GetDirectoryName(toZipFilePath);
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        File.Delete(toZipFilePath);
        ZipFile.CreateFromDirectory(fromFilePath, toZipFilePath);
        using (zipArchive = ZipFile.Open(toZipFilePath, ZipArchiveMode.Update))
        {
            foreach (var item in otherFiles)
            {
                zipArchive.CreateEntryFromFile(item, Path.GetFileName(item));
            }
        }
        return toZipFilePath;
    }

    public bool UnzipFile(string zip_path, string to_path)
    {
        if (Directory.Exists(to_path)) Directory.Delete(to_path, true);
        Directory.CreateDirectory(to_path);
        using (ZipArchive zipArchive = ZipFile.Open(zip_path, ZipArchiveMode.Read))
        {
            zipArchive.ExtractToDirectory(to_path, true);
        }

        return true;
    }
    /// <summary>
    /// 从zip中获取指定文件名文件的内容
    /// </summary>
    /// <param name="zip_path"></param>
    /// <param name="target_filename"></param>
    /// <returns></returns>
    public byte[] GetFileFromZip(string zip_path, string target_filename)
    {
        using (ZipArchive zipArchive = ZipFile.Open(zip_path, ZipArchiveMode.Read))
        {
            foreach (ZipArchiveEntry entry in zipArchive.Entries)
            {
                if (entry.Name == "target_filename")
                {
                    using (Stream stream = entry.Open())
                    {
                        return ComFunc.StreamToBytes(stream);
                    }
                }
            }

            return null;
        }
    }
    public byte[] GetFileFromZip(byte[] filecontent, string target_filename)
    {
        using (var zipArchive = new ZipArchive(new MemoryStream(filecontent)))
        {
            var entry = zipArchive.GetEntry(target_filename);
            if (entry == null)
            {
                return null;
            }
            using (var stream = entry.Open())
            {
                var sr = new StreamReader(stream);
                var str = sr.ReadToEnd();
                return Encoding.UTF8.GetBytes(str);
            }
        }
    }
}
}